package com.reebake.ideal.message.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.reebake.ideal.cache.helper.TimesCacheHelper;
import com.reebake.ideal.captcha.core.SmartCaptchaService;
import com.reebake.ideal.captcha.entity.CaptchaRequestEntity;
import com.reebake.ideal.captcha.entity.CaptchaResponseEntity;
import com.reebake.ideal.captcha.exception.CaptchaVerifyFailureException;
import com.reebake.ideal.message.core.MessageTypeConstants;
import com.reebake.ideal.message.entity.MessageVerifyCodeEntity;
import com.reebake.ideal.message.entity.TemplateMessageSendDTO;
import com.reebake.ideal.message.properties.MessageProperties;
import com.reebake.ideal.message.service.MessageOperationService;
import com.reebake.ideal.message.service.MessageVerifyCodeService;
import com.reebake.ideal.verify.code.core.VerifyCodeGenerator;
import com.reebake.ideal.verify.code.core.VerifyCodeService;
import com.reebake.ideal.verify.code.entity.VerifyCodeEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.LinkedHashMap;

@Service
public class MessageVerifyCodeServiceImpl implements MessageVerifyCodeService {
    @Autowired
    private VerifyCodeService verifyCodeService;
    @Autowired
    private VerifyCodeGenerator verifyCodeGenerator;
    @Autowired
    private SmartCaptchaService smartCaptchaService;
    @Autowired
    private MessageOperationService messageOperationService;
    @Autowired
    private MessageProperties messageProperties;

    private static final String CACHE_PREFIX_USERNAME = "verify-code:times:captcha:username";
    private final TimesCacheHelper usernameTimesCacheHelper = new TimesCacheHelper(CACHE_PREFIX_USERNAME, 24*60*60*1000);

    @Override
    public Boolean requireCaptcha(String username) {
        long usernameTimes = usernameTimesCacheHelper.getTimes(username);
        long usernameTriggerCaptchaTimes = messageProperties.getVerifyCode().getUsernameTriggerCaptchaTimes();
        if(usernameTriggerCaptchaTimes >0 && usernameTimes > usernameTriggerCaptchaTimes) {
            return true;
        }
        return false;
    }

    @Override
    public void sendVerifyCode(MessageVerifyCodeEntity verifyCodeEntity) {
        String username = verifyCodeEntity.getUsername();
        Assert.notBlank(username);
        if(requireCaptcha(username)) {
            CaptchaResponseEntity result = smartCaptchaService.verify(BeanUtil.copyProperties(verifyCodeEntity, CaptchaRequestEntity.class));
            if(!result.isSuccess()) {
                throw new CaptchaVerifyFailureException();
            }
        }
        this.sendVerifyCode(username);

        usernameTimesCacheHelper.increase(username);
    }

    public void sendVerifyCode(String receiver) {
        LinkedHashMap<String, String> param = new LinkedHashMap<>();
        String verifyCode = verifyCodeGenerator.generate();
        param.put("verifyCode", verifyCode);
        TemplateMessageSendDTO messageSendDTO = new TemplateMessageSendDTO();
        messageSendDTO.setMessageType(MessageTypeConstants.VERIFY_CODE);
        messageSendDTO.setParam(param);
        messageSendDTO.setReceiverIds(receiver);
        messageOperationService.sendTemplate(messageSendDTO);
        VerifyCodeEntity verifyCodeEntity = new VerifyCodeEntity();
        verifyCodeEntity.setVerifyCode(verifyCode);
        verifyCodeEntity.setReceiver(receiver);
        verifyCodeService.save(verifyCodeEntity);
    }

    @Override
    public Boolean verify(MessageVerifyCodeEntity verifyCodeEntity) {
        String username = verifyCodeEntity.getUsername();
        if(StrUtil.isBlank(username)) {
            return false;
        }
        if(requireCaptcha(username)) {
            CaptchaResponseEntity result = smartCaptchaService.verify(BeanUtil.copyProperties(verifyCodeEntity, CaptchaRequestEntity.class));
            if(!result.isSuccess()) {
                throw new CaptchaVerifyFailureException();
            }
        }
        String verifyCode = verifyCodeEntity.getVerifyCode();
        return verifyCodeService.check(username, verifyCode);
    }

}
